﻿using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Google.API.Predict;
using Google.API.Predict.Requests.Features;
using Google.API.Predict.Responses;

namespace PredictionGUI
{
    public partial class Form1 : Form
    {
        GooglePredictionClient _client;
        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            lblTrainStatus.Text = string.Empty;
            lblOutputLabel.Text = string.Empty;
        }

        GooglePredictionClient client
        {
            get
            {
                if (_client == null)
                {
                    createClient();
                }
                
                return _client;
            }
        }

        private void createClient()
        {
            if (checkBox1.CheckState == CheckState.Checked)
            {
                _client = new GooglePredictionClient(txtAuth.Text, txtBucket.Text, txtData.Text);
                credsBox.BackColor = Color.FromArgb(255, 255, 192);
            }
            else
            {
                _client = new GooglePredictionClient(txtEmail.Text, txtPassword.Text, txtBucket.Text, txtData.Text);
                //credsBox.BackColor = _client.ClientLogin.ErrorCode == ClientLoginErrorCode.None ? Color.FromKnownColor(KnownColor.Control) : Color.FromArgb(255, 192, 192);

                //if (_client.ClientLogin.ErrorCode != ClientLoginErrorCode.None)
                    //MessageBox.Show("Error - " + _client.ClientLogin.ErrorCode.ToString());

                txtAuth.Text = _client.ClientLogin.Auth;
            }

            btnStatus.Enabled = btnTrain.Enabled = btnPredict.Enabled = true;//_client.ClientLogin.ErrorCode == ClientLoginErrorCode.None;
        }

        private void btnStatus_Click(object sender, EventArgs e)
        {
            client.ChangeData(txtBucket.Text, txtData.Text);
            Properties.Settings.Default.Bucket = txtBucket.Text;
            Properties.Settings.Default.Data = txtData.Text;
            Properties.Settings.Default.Save();
            lblTrainStatus.Text = "Checking status...";
            this.Refresh();
            var r = client.Check();
            if (r.Success)
            {
                lblTrainStatus.Text = r.Data + " - " + r.ModelInfo;
            }
            else
            {
                lblTrainStatus.Text = r.ResponseStatusCodeDescription;
            }
        }

        private void btnTrain_Click(object sender, EventArgs e)
        {
            client.ChangeData(txtBucket.Text, txtData.Text);
            Properties.Settings.Default.Bucket = txtBucket.Text;
            Properties.Settings.Default.Data = txtData.Text;
            Properties.Settings.Default.Save();
            lblTrainStatus.Text = "Invoking training...";
            this.Refresh();
            var tr = client.Train();
            if (tr.Success)
            {
                if (tr.TrainingInvoked)
                {
                    lblTrainStatus.Text = "Training invoked...";
                    this.Refresh();
                }

                var r = client.Check();
                if (r.Success)
                {
                    lblTrainStatus.Text = r.Data + " - " + r.ModelInfo;
                }
                else
                {
                    lblTrainStatus.Text = r.ResponseStatusCodeDescription;
                }
            }
            else
            {
                lblTrainStatus.Text = tr.ResponseStatusCodeDescription;
            }
        }

        private void btnPredict_Click(object sender, EventArgs e)
        {
            client.ChangeData(txtBucket.Text, txtData.Text);
            Properties.Settings.Default.Bucket = txtBucket.Text;
            Properties.Settings.Default.Data = txtData.Text;
            Properties.Settings.Default.Save();
            if (txtInput.Lines.Length > 0)
            {
                lblOutputLabel.Text = "Requesting prediction...";
                lstMulti.Items.Clear();
                this.Refresh();
                PredictionResponse o;
                if (ddlType.SelectedIndex <= 0)
                {
                    TextFeatures tp = new TextFeatures(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).ToArray());
                    o = client.PredictText(tp);
                }
                else if (ddlType.SelectedIndex == 1) // int
                {
                    NumericFeatures<int> np = new NumericFeatures<int>(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).Select(l => int.Parse(l.Trim())).ToArray());
                    o = client.PredictNumeric(np);
                }
                else if (ddlType.SelectedIndex == 2) // long
                {
                    NumericFeatures<long> np = new NumericFeatures<long>(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).Select(l => long.Parse(l.Trim())).ToArray());
                    o = client.PredictNumeric(np);
                }
                else if (ddlType.SelectedIndex == 3) // float
                {
                    NumericFeatures<float> np = new NumericFeatures<float>(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).Select(l => float.Parse(l.Trim())).ToArray());
                    o = client.PredictNumeric(np);
                }
                else if (ddlType.SelectedIndex == 4) // double
                {
                    NumericFeatures<double> np = new NumericFeatures<double>(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).Select(l => double.Parse(l.Trim())).ToArray());
                    o = client.PredictNumeric(np);
                }
                else if (ddlType.SelectedIndex == 5) // decimal
                {
                    NumericFeatures<decimal> np = new NumericFeatures<decimal>(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).Select(l => decimal.Parse(l.Trim())).ToArray());
                    o = client.PredictNumeric(np);
                }
                else
                {
                    MixedFeatures np = new MixedFeatures(txtInput.Lines.Where(l => !string.IsNullOrEmpty(l)).Select(l =>
                        {
                            int t;
                            long g;
                            float f;
                            double d;                            
                            decimal c;

                            bool ip = int.TryParse(l.Trim(), out t);
                            bool lp = long.TryParse(l.Trim(), out g);
                            bool fp = float.TryParse(l.Trim(), out f);
                            bool dp = double.TryParse(l.Trim(), out d);
                            bool cp = decimal.TryParse(l.Trim(), out c);

                            if (ip && l.Equals(t.ToString(System.Globalization.CultureInfo.InvariantCulture)))
                                return (object)t;

                            if (lp && l.Equals(g.ToString(System.Globalization.CultureInfo.InvariantCulture)))
                                return (object)g;

                            if (fp && l.Equals(f.ToString(System.Globalization.CultureInfo.InvariantCulture)))
                                return (object)f;

                            if (dp && l.Equals(d.ToString(System.Globalization.CultureInfo.InvariantCulture)))
                                return (object)d;

                            if (cp && l.Equals(c.ToString(System.Globalization.CultureInfo.InvariantCulture)))
                                return (object)c;

                            return (object)l;

                        }).ToArray());
                    
                    o = client.PredictMixed(np);
                }

                if (o.Success)
                {
                    if (o.OutputType == PredictionResponse.PredictionOutputType.Categorical)
                    {
                        lblOutputLabel.Text = o.OutputLabel;
                        lstMulti.Items.AddRange(o.OutputMulti.Select(m =>
                            {
                                var l = new ListViewItem(m.Label);
                                l.SubItems.Add(m.Score.ToString());
                                return l;
                            }).ToArray());
                    }
                    else
                    {
                        lblOutputLabel.Text = o.OutputValue;
                    }
                }
                else
                {
                    lblOutputLabel.Text = o.ResponseStatusCodeDescription;
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ddlType.SelectedIndex = 0;
            btnStatus.Enabled = btnTrain.Enabled = btnPredict.Enabled = false;

            txtEmail.Text = Properties.Settings.Default.UserName;
            txtAuth.Text = Properties.Settings.Default.AuthKey;
            checkBox1.Checked = Properties.Settings.Default.UseAuth;
            rememberKey.Checked = Properties.Settings.Default.SaveAuth;
            txtBucket.Text = Properties.Settings.Default.Bucket;
            txtData.Text = Properties.Settings.Default.Data;
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            createClient();
            btnStatus.Enabled = btnTrain.Enabled = btnPredict.Enabled = _client != null;// && _client.ClientLogin.ErrorCode == ClientLoginErrorCode.None;

            if (_client != null)//l && _client.ClientLogin.ErrorCode == ClientLoginErrorCode.None && Properties.Settings.Default.SaveAuth)
            {
                Properties.Settings.Default.AuthKey = _client.ClientLogin.Auth;
                Properties.Settings.Default.Save();
            }

            if (!string.IsNullOrEmpty(txtEmail.Text))
            {
                Properties.Settings.Default.UserName = txtEmail.Text;
                Properties.Settings.Default.Save();
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.UseAuth = checkBox1.CheckState == CheckState.Checked;

            if (checkBox1.CheckState != CheckState.Checked)
                Properties.Settings.Default.AuthKey = "";

            Properties.Settings.Default.Save();
        }

        private void rememberKey_CheckedChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.SaveAuth = rememberKey.CheckState == CheckState.Checked;
            Properties.Settings.Default.Save();
        }

        private void btnDeleteModel_Click(object sender, EventArgs e)
        {
            client.ChangeData(txtBucket.Text, txtData.Text);
            lblTrainStatus.Text = "Deleting " + txtBucket.Text + "/" + txtData.Text + ".";
            this.Refresh();
            var dr = client.Delete();
            if (dr.Success)
            {
                lblTrainStatus.Text = "Deleted " + txtBucket.Text + "/" + txtData.Text + "!";
            }
            else
            {
                lblTrainStatus.Text = dr.ResponseStatusCodeDescription;
            }
        }
    }
}
